﻿using ICPFrameLib.Business;
using ICPFrameLib.Attributes;
using XHRPMIS.Common;
using EFFC.Frame.Net.Base.Common;
using EFFC.Frame.Net.Base.Data.Base;
using EFFC.Frame.Net.Module.Extend.EWRA.Attributes;
using EFFC.Frame.Net.Module.Extend.EWRA.Attributes.Validation;
using EFFC.Frame.Net.Unit.DB.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using EFFC.Extends.LinqDLR2SQL;
using EFFC.Frame.Net.Unit.DB;
using EFFC.Frame.Net.Base.Data;
using System.IO;
using EFFC.Frame.Net.Base.Constants;
using System.Text.RegularExpressions;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using System.Text;
using ICPFrameLib.Common;
using EFFC.Frame.Net.Unit.DB.Datas;

namespace XHRPMIS.Business.v1._0
{
   public partial class MetaDynamicForm
{
    #region OpenAPI
    [EWRARouteDesc("根据指定表中指定栏位的引用资料抓取关联表中的数据（用于通过关系表来获取子表的数据）")]
    [EWRARoute("post", "/md_form/{id}/ref_query")]
    [EWRAAddInput("id", "string", "元数据表uid", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("limit", "int", "每页笔数，当mode为Normal时需要提供", "默认为10", EFFC.Frame.Net.Base.Constants.RestInputPosition.QueryString, true)]
    [EWRAAddInput("page", "int", "指定页数，当mode为Normal时需要提供", "默认为1", EFFC.Frame.Net.Base.Constants.RestInputPosition.QueryString, true)]
    [EWRAAddInput("ref_info", "object", @"{
column:'关联栏位名称，通过该栏位获取对应的table信息',
filter_express:'固定过滤条件表达式，采用DBExpress的$where表达式写法，传入时采用base64+urlcode编码方式'
}", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, false)]
    [EWRAAddInput("target_info", "object", @"{
is_filter_deleted:'bool,是否过滤掉逻辑删除的资料',
filter_column:'过滤条件的栏位名称',
filter_value:'过滤条件的值',
query_columns:'要抓取的栏位，多个用逗号分隔',
fixed_filter_express:""固定过滤条件表达式，采用DBExpress的$where表达式写法，传入时采用base64+urlcode编码方式；
表达式中可以使用一些基础变量，如下：
__login_id:当前登录者ID,
__login_name:当前登录者的登录名称
__user_no:登录信息中的userno值,
__no:登录信息中的no值,
__user_name:登录信息中的username值,
__user_type:登录信息中的usertype值,
__role_no:当前登录者系统角色编号，多个,
__role_name:当前登录者系统角色名称，多个,
__now:当前时间，格式yyyy-MM-dd HH:mm:ss"",
fixed_orderby_express:'固定排序表达式，采用DBExpress的$orderby表达式写法，传入时采用base64+urlcode编码方式',
other_condition_express:""其它查询条件表达式，采用DBExpress的$orderby表达式写法，传入时采用base64+urlcode编码方式,
注意:1.如果条件表达式中存在值为空的项目时，会自动过滤
2.如果表达式中的key与fixed_filter_express存在重复时，会自动覆盖fixed_filter_express中的条件表达式，所以如果同一个key在fixed_filter_express和other_condition_express中重复时，请将这两项手工合并到一处
表达式中可以使用一些基础变量，如下：
界面上的参数用“@key@”来表示,
__login_id: 当前登录者ID,
__login_name: 当前登录者的登录名称
__user_no: 登录信息中的userno值,
__no: 登录信息中的no值,
__user_name: 登录信息中的username值,
__user_type: 登录信息中的usertype值,
__role_no: 当前登录者系统角色编号，多个,
__role_name: 当前登录者系统角色名称，多个,
__now: 当前时间，格式yyyy - MM - dd HH: mm:ss""
}", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
total_count:'总笔数',
page:'当前页数',
total_page:'总页数',
limit:'每页笔数',
data:[元数据的结果集,如果栏位有reference关联信息的会自动带上一个text值，如：bh栏位，会自动新增一个bh__text的栏位]
}")]
    public object QueryRefList(string id)
    {
        SetCacheEnable(false);
        var ref_info = PostDataD.ref_info;
        var target_info = PostDataD.target_info;
        if (ref_info == null)
        {
            return new
            {
                code = "failed",
                msg = "ref_info信息不可为空"
            };
        }
        if (target_info == null) target_info = FrameDLRObject.CreateInstance();
        string ref_column = ComFunc.nvl(ref_info.column);
        string ref_filter_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(ref_info.filter_express));
        var ref_filter_express_obj = parseFixedExpress(ref_filter_express);
        if (ref_filter_express != "" && ref_filter_express_obj == null)
        {
            return new
            {
                code = "failed",
                msg = "ref_info.filter_express格式不正确"
            };
        }

        bool is_filter_deleted = BoolStd.IsNotBoolThen(target_info.is_filter_deleted, true);
        string parent_pk = "";
        string filter_column = ComFunc.nvl(target_info.filter_column);
        string filter_value = ComFunc.nvl(target_info.filter_value);
        string query_columns = ComFunc.nvl(target_info.query_columns);
        string fixed_filter_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(target_info.fixed_filter_express));
        string fixed_orderby_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(target_info.fixed_orderby_express));
        string other_condition_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(target_info.other_condition_express));
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        //优化查询
        //dynamic ref_metainfo = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
        //                        where (t.metauid == id || t.metaname == id) && t.IsCreated == 1
        //                        select t).GetQueryList(up).FirstOrDefault();
        var ref_metainfo = MetaDataUtilities.GetAllTables(metaup).Where(w => w.MetaUID == id || w.MetaName == id).FirstOrDefault();
        if (ref_metainfo == null)
        {
            return new
            {
                code = "failed",
                msg = "元数据表不存在或未创建"
            };
        }
        //优化查询
        //dynamic ref_columninfo = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
        //                          where t.MetaUID == ref_metainfo.MetaUID && t.MetaColumnName == ref_column
        //                          select t).GetQueryList(up).FirstOrDefault();
        var ref_columninfo = ref_metainfo.columns.Where(w => w.MetaColumnName == ref_column && !w.IsVirsual).FirstOrDefault();
        if (ref_columninfo == null)
        {
            return new
            {
                code = "failed",
                msg = "指定引用栏位不存在"
            };
        }
        var ref_refResult = ref_express.ParseExpress(ComFunc.nvl(ref_columninfo.MetaReference));
        var target_table = ref_refResult.TableName;

        //object rtn = null;
        //string msg = "";
        //if (DoQueryList(ref msg, ref rtn, metaup, up, target_table, is_filter_deleted, parent_pk, filter_column, filter_value, query_columns, new_fixed_filter_express_obj.ToJSONString(), fixed_orderby_express, other_condition_express))
        //{
        //    return rtn;
        //}
        //else
        //{
        //    return new
        //    {
        //        code = "failed",
        //        msg
        //    };
        //}
        var orderby_fixed_filter_express = FrameDLRObject.IsJsonThen(fixed_orderby_express, null, FrameDLRFlags.SensitiveCase);

        var where_fixed_filter_express = parseFixedExpress(fixed_filter_express);
        var where_other_condition_express = parseFixedExpress(other_condition_express);

        if (fixed_filter_express != "" && where_fixed_filter_express == null)
        {
            return new
            {
                code = "failed",
                msg = "target.fixed_filter_express格式不正确"
            };
        }
        if (fixed_orderby_express != "" && orderby_fixed_filter_express == null)
        {
            return new
            {
                code = "failed",
                msg = "target.fixed_orderby_express格式不正确"
            };
        }

        var q_columns = query_columns.Split(",", StringSplitOptions.RemoveEmptyEntries);
        //查询优化
        //dynamic target_metainfo = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA", "a")
        //                           where (t.metauid == target_table || t.metaname == target_table) && t.IsCreated == 1
        //                           select t).GetQueryList(metaup).FirstOrDefault();
        var target_metainfo = MetaDataUtilities.GetAllTables(metaup).Where(w => (w.MetaUID == target_table || w.MetaName == target_table) && w.IsCreated).FirstOrDefault();
        if (target_metainfo == null)
        {
            return new
            {
                code = "failed",
                msg = "Target元数据表不存在"
            };
        }
        string tablename = target_metainfo.MetaName;
        string main_ref = ComFunc.nvl(target_metainfo.MetaMainUID);
        string main_ref_show = ComFunc.nvl(target_metainfo.MetaMainShowColumn);
        //查询优化
        //var columns = (from t in DB.LamdaTable(metaup, "EXTEND_METADATA_COLUMNS", "a")
        //               orderby t.sortnum
        //               where t.metauid == target_metainfo.metauid && t.isshow == 1 && t.IsVirsual == 0
        //               select new
        //               {
        //                   column_name = t.MetaColumnName,
        //                   column_desc = t.MetaColumnDesc,
        //                   data_type = t.MetaDataType,
        //                   reference = t.MetaReference,
        //                   is_allow_empty = t.MetaAllowEmpty,
        //                   is_pk = t.MetaIsPK,
        //                   sort_num = t.SortNum,
        //                   is_show = t.IsShow,
        //                   format = t.MetaFormat
        //               }).GetQueryList(metaup);
        var columns = target_metainfo.columns.Where(w => !w.IsVirsual).ToList();
        //过滤要抓取的栏位
        columns = q_columns.Length <= 0 ? columns : columns.Where(d => q_columns.Contains(d.MetaColumnName)).ToList();
        // 固定带上以下栏位
        columns.AddRange(MetaDataUtilities.FixColumnsModel);

        var datatype_dic = columns.ToDictionary(k => k.MetaColumnName, v => v.MetaDataType);
        #region 构建select表达式
        FrameDLRObject express = FrameDLRObject.CreateInstance(@"{
'$acttype' : 'QueryByPage'
}", EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);
        var tableexpress = FrameDLRObject.CreateInstance(@"{
'" + target_table + @"':'a',
'" + ref_metainfo.MetaName + @"':{
    $as:'b',
    $join:{
        $on:{
            '#column:a." + ref_refResult.KeyColumn + @"':'#column:b." + ref_column + @"'
        }
    }
}
}", FrameDLRFlags.SensitiveCase);
        express.SetValue("$table", tableexpress);
        //order by
        FrameDLRObject orderby = orderby_fixed_filter_express == null ? FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase) : orderby_fixed_filter_express;
        foreach (var key in orderby.Keys)
        {
            orderby.SetValue($"{key}", orderby.GetValue(key));
        }
        orderby.SetValue("#column:a.sort_no", "asc");
        express.SetValue("$orderby", orderby);

        foreach (var c in columns)
        {
            //设定select的栏位
            express.SetValue($"#column:a.{c.MetaColumnName}", true);
        }
        FrameDLRObject where = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
        if (where_fixed_filter_express != null)
        {
            foreach (var key in where_fixed_filter_express.Keys)
            {
                where.SetValue($"#column:a.{key}", where_fixed_filter_express.GetValue(key));
            }
        }
        if (is_filter_deleted) where.SetValue("#column:a._is_deleted", 0);
        if (parent_pk != "") where.SetValue("#column:a._default_parent_pk", parent_pk);
        if (!string.IsNullOrEmpty(filter_column))
        {
            var fc = filter_column.Split(',', StringSplitOptions.RemoveEmptyEntries);
            var orlist = new List<FrameDLRObject>();
            where.SetValue("$or", orlist);
            foreach (var f in fc)
            {
                FrameDLRObject exp = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
                exp.SetValue("$like", filter_value);
                var fexp = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
                fexp.SetValue(f, exp);
                orlist.Add(fexp);
            }
        }
        //ref条件
        if (ref_filter_express_obj != null)
        {
            RemoveFilterEmptry(ref_filter_express_obj);
            foreach (var key in ref_filter_express_obj.Keys)
            {
                if (ComFunc.nvl(ref_filter_express_obj.GetValue(key)) != "")
                {
                    where.SetValue($"#column:b.{key}", ref_filter_express_obj.GetValue(key));
                }
            }
        }
        //其它查询条件
        if (where_other_condition_express != null)
        {
            RemoveFilterEmptry(where_other_condition_express);
            foreach (var key in where_other_condition_express.Keys)
            {
                if (ComFunc.nvl(where_other_condition_express.GetValue(key)) != "")
                {
                    where.SetValue($"#column:a.{key}", where_other_condition_express.GetValue(key));
                }
            }
        }

        if (where.Items.Count > 0)
        {
            express.SetValue("$where", where);
        }
        #endregion
        var result = DB.Excute(up, express, true);
        var data = result.QueryData<FrameDLRObject>();
        #region 处理各个栏位的UI数据和关联项
        SetRefColumnsText(metaup, up, target_metainfo, columns, data, false);
        #endregion
        // 对数据中字符串的特殊符号做过滤
        data = FilterSpecialChar4List(data);
        return new
        {
            code = "success",
            msg = "",
            total_count = result.TotalRow,
            page = result.CurrentPage,
            total_page = result.TotalPage,
            limit = result.Count_Of_OnePage,
            data = data
        };
    }

    [EWRARouteDesc("获取指定元数据表中的数据列表")]
    [EWRARoute("post", "/md_form/{id}/query")]
    [EWRAAddInput("id", "string", "元数据表uid", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("limit", "int", "每页笔数，当mode为Normal时需要提供", "默认为10", EFFC.Frame.Net.Base.Constants.RestInputPosition.QueryString, true)]
    [EWRAAddInput("page", "int", "指定页数，当mode为Normal时需要提供", "默认为1", EFFC.Frame.Net.Base.Constants.RestInputPosition.QueryString, true)]
    [EWRAAddInput("is_filter_deleted", "bool", "是否过滤掉逻辑删除的资料", "默认为true", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("parent_pk", "string", "父节点PK，当该值不为空时则自动抓取其子节点的列表", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("filter_column", "string", "过滤条件的栏位名称", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("filter_value", "string", "过滤条件的值", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("query_columns", "string", "要抓取的栏位，多个用逗号分隔", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("fixed_filter_express", "string", @"固定过滤条件表达式，采用DBExpress的$where表达式写法，传入时采用base64+urlcode编码方式；
表达式中的特殊条件如下：
$tree_in:单表数据结构条件查询，自动根据值及其子节点值查询符合条件的资料，的条件中的栏位必须为cadecase_tree、multi_cadecase_tree，并且引用表达式存在才生效，否则变为普通的$in操作，
$main_tree_in:主从表树数据结构条件查询，值结构与$in一样，自动根据值及其子节点值查询符合条件的资料，条件中的栏位必须为cadecase_main、multi_cadecase_main，并且引用表达式存在才生效，否则变为普通的$in操作
表达式中可以使用一些基础变量，如下：
__login_id:当前登录者ID,
__login_name:当前登录者的登录名称
__user_no:登录信息中的userno值,
__no:登录信息中的no值,
__user_name:登录信息中的username值,
__user_type:登录信息中的usertype值,
__role_no:当前登录者系统角色编号，多个,
__role_name:当前登录者系统角色名称，多个,
__now:当前时间，格式yyyy-MM-dd HH:mm:ss
", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("fixed_orderby_express", "string", "固定排序表达式，采用DBExpress的$orderby表达式写法，传入时采用base64+urlcode编码方式", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("other_condition_express", "string", @"其它查询条件表达式，采用DBExpress的$orderby表达式写法，传入时采用base64+urlcode编码方式,
注意:1.如果条件表达式中存在值为空的项目时，会自动过滤
2.如果表达式中的key与fixed_filter_express存在重复时，会自动覆盖fixed_filter_express中的条件表达式，所以如果同一个key在fixed_filter_express和other_condition_express中重复时，请将这两项手工合并到一处
表达式中的特殊条件如下：
$tree_in:单表数据结构条件查询，自动根据值及其子节点值查询符合条件的资料，的条件中的栏位必须为cadecase_tree、multi_cadecase_tree，并且引用表达式存在才生效，否则变为普通的$in操作
表达式中可以使用一些基础变量，如下：
界面上的参数用“@key@”来表示,
__login_id: 当前登录者ID,
__login_name: 当前登录者的登录名称
__user_no: 登录信息中的userno值,
__no: 登录信息中的no值,
__user_name: 登录信息中的username值,
__user_type: 登录信息中的usertype值,
__role_no: 当前登录者系统角色编号，多个,
__role_name: 当前登录者系统角色名称，多个,
__now: 当前时间，格式yyyy - MM - dd HH: mm:ss", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
total_count:'总笔数',
page:'当前页数',
total_page:'总页数',
limit:'每页笔数',
data:[元数据的结果集,如果栏位有reference关联信息的会自动带上一个text值，如：bh栏位，会自动新增一个bh__text的栏位]
}")]
    public object QueryList(string id)
    {
        SetCacheEnable(false);
        bool is_filter_deleted = BoolStd.IsNotBoolThen(PostDataD.is_filter_deleted, true);
        string parent_pk = ComFunc.nvl(PostDataD.parent_pk);
        string filter_column = ComFunc.nvl(PostDataD.filter_column);
        string filter_value = ComFunc.nvl(PostDataD.filter_value);
        string query_columns = ComFunc.nvl(PostDataD.query_columns);
        string fixed_filter_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.fixed_filter_express));
        string fixed_orderby_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.fixed_orderby_express));
        string other_condition_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.other_condition_express));
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        object rtn = null;
        string msg = "";
        if (DoQueryList(ref msg, ref rtn, metaup, up, id, is_filter_deleted, parent_pk, filter_column, filter_value, query_columns, fixed_filter_express, fixed_orderby_express, other_condition_express))
        {
            return rtn;
        }
        else
        {
            return new
            {
                code = "failed",
                msg
            };
        }
    }


    [EWRARouteDesc("获取指定元数据表中的数据列表")]
    [EWRARoute("get", "/md_form/{id}/query/{pk}")]
    [EWRAAddInput("id", "string", "元数据表uid", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("pk", "string", "资料的PK", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
data:{元数据的结果集,如果栏位有reference关联信息的会自动带上一个text值，如：bh栏位，会自动新增一个bh__text的栏位}
}")]
    public object QueryDetail(string id, string pk)
    {
        SetCacheEnable(false);

        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        var info = MetaDataUtilities.GetAllTables(metaup).Where(w => (w.MetaUID == id || w.MetaName == id) && w.IsCreated).FirstOrDefault();
        if (info == null)
        {
            return new
            {
                code = "failed",
                msg = "元数据表不存在",
            };
        }
        string tablename = info.MetaName;
        string main_ref = ComFunc.nvl(info.MetaMainUID);
        string main_ref_show = ComFunc.nvl(info.MetaMainShowColumn);
        var columns = info.columns.Where(w => !w.IsVirsual).ToList();
        #region 固定带上以下栏位
        columns.AddRange(MetaDataUtilities.FixColumnsModel);
        #endregion
        #region 构建select表达式
        FrameDLRObject express = FrameDLRObject.CreateInstance(@"{
$acttype : 'Query',
                }", EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);

        foreach (var c in columns)
        {
            //设定select的栏位
            express.SetValue($"{c.MetaColumnName}", true);
        }
        express.SetValue("$table", tablename);
        FrameDLRObject where = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
        where.SetValue("_default_pk", pk);
        express.SetValue("$where", where);
        #endregion
        var result = DB.Excute(up, express, true);
        var resultlist = result.QueryData<FrameDLRObject>();
        if (resultlist.Count <= 0)
        {
            return new
            {
                code = "failed",
                msg = "资料不存在"
            };
        }
        #region 处理各个栏位的UI数据和关联项
        SetRefColumnsText(metaup, up, info, columns, resultlist, false);
        #endregion
        var data = resultlist.FirstOrDefault();
        #region 获取所有从表资料
        var subs = FrameDLRObject.CreateInstance();
        data.SetValue("subs", subs);
        var sub_metas = MetaDataUtilities.GetAllTables(metaup).Where(w => w.MetaMainUID == id && w.IsCreated).ToList();
        foreach (var subm in sub_metas)
        {
            string subtablename = subm.MetaName;
            var subcolumns = subm.columns.Where(w => w.IsShow && !w.IsVirsual).ToList();

            subcolumns.AddRange(MetaDataUtilities.FixColumnsModel);
            #region 构建select表达式
            FrameDLRObject subexpress = FrameDLRObject.CreateInstance(@"{
$acttype : 'Query',
                }", EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);


            foreach (var c in subcolumns)
            {
                //设定select的栏位
                subexpress.SetValue($"{c.MetaColumnName}", true);
            }
            subexpress.SetValue("$table", subtablename);
            FrameDLRObject subwhere = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
            subwhere.SetValue("_default_ref", pk);
            subexpress.SetValue("$where", subwhere);
            #endregion
            var subresult = DB.Excute(up, subexpress, true);
            var subdata = subresult.QueryData<FrameDLRObject>();

            SetRefColumnsText(metaup, up, subm, subcolumns, subdata, false);
            subs.SetValue(subtablename, subdata);
        }
        #endregion

        return new
        {
            code = "success",
            msg = "",
            data = data
        };
    }
    [EWRARouteDesc("获取指定元数据表中的数据列表-按照自定义条件获取")]
    [EWRARoute("post", "/md_form/{id}/query/detail")]
    [EWRAAddInput("id", "string", "元数据表uid", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.Path, false)]
    [EWRAAddInput("is_filter_deleted", "bool", "是否过滤掉逻辑删除的资料", "默认为true", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("parent_pk", "string", "父节点PK，当该值不为空时则自动抓取其子节点的列表", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("query_columns", "string", "要抓取的栏位，多个用逗号分隔", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAAddInput("filter_express", "string", @"固定过滤条件表达式，采用DBExpress的$where表达式写法，传入时采用base64+urlcode编码方式；
表达式中的特殊条件如下：
$tree_in:单表数据结构条件查询，自动根据值及其子节点值查询符合条件的资料，的条件中的栏位必须为cadecase_tree、multi_cadecase_tree，并且引用表达式存在才生效，否则变为普通的$in操作，
表达式中可以使用一些基础变量，如下：
__login_id:当前登录者ID,
__login_name:当前登录者的登录名称
__user_no:登录信息中的userno值,
__no:登录信息中的no值,
__user_name:登录信息中的username值,
__user_type:登录信息中的usertype值,
__role_no:当前登录者系统角色编号，多个,
__role_name:当前登录者系统角色名称，多个,
__now:当前时间，格式yyyy-MM-dd HH:mm:ss
", "无默认值", EFFC.Frame.Net.Base.Constants.RestInputPosition.PostData, true)]
    [EWRAOutputDesc("返回结果", @"{
code:'success-成功，failed-失败',
msg:'提示信息',
data:{元数据的结果集,如果栏位有reference关联信息的会自动带上一个text值，如：bh栏位，会自动新增一个bh__text的栏位}
}")]
    public object QueryDetail(string id)
    {
        SetCacheEnable(false);
        bool is_filter_deleted = BoolStd.IsNotBoolThen(PostDataD.is_filter_deleted, true);
        string query_columns = ComFunc.nvl(PostDataD.query_columns);
        string parent_pk = ComFunc.nvl(PostDataD.parent_pk);
        string filter_express = ComFunc.UrlDecode(ComFunc.IsBase64Then(PostDataD.filter_express));
        var metaup = DB.NewMetaUnitParameter();
        var up = DB.NewDBUnitParameter();
        object rtn = null;
        string msg = "";
        if (DoQueryList(ref msg, ref rtn, metaup, up, id, is_filter_deleted, parent_pk, "", "", query_columns, filter_express, "", ""))
        {
            var dobj = FrameDLRObject.CreateInstance(rtn);
            if (dobj.code == "success")
            {
                var data = dobj.data as List<FrameDLRObject>;
                if (data.Count <= 0)
                {
                    return new
                    {
                        code = "failed",
                        msg = "资料不存在"
                    };
                }
                else
                {
                    return new
                    {
                        code = "success",
                        msg = "",
                        data = data.First()
                    };
                }
            }
            else
            {
                return rtn;
            }
        }
        else
        {
            return new
            {
                code = "failed",
                msg
            };
        }
    }
    #endregion

    #region LocalFunction
    /// <summary>
    /// 执行元数据表的查询
    /// </summary>
    /// <param name="msg">错误信息提示</param>
    /// <param name="out_result">返回的结果对象</param>
    /// <param name="metaup"></param>
    /// <param name="up"></param>
    /// <param name="id">元数据表UID或name</param>
    /// <param name="is_filter_deleted">是否过滤掉逻辑删除的资料</param>
    /// <param name="parent_pk">父节点PK，当该值不为空时则自动抓取其子节点的列表</param>
    /// <param name="filter_column">过滤条件的栏位名称</param>
    /// <param name="filter_value">过滤条件的值</param>
    /// <param name="query_columns">要抓取的栏位，多个用逗号分隔</param>
    /// <param name="fixed_filter_express">固定过滤条件表达式，采用DBExpress的$where表达式写法，传入时采用base64+urlcode编码方式</param>
    /// <param name="fixed_orderby_express">固定排序表达式，采用DBExpress的$orderby表达式写法，传入时采用base64+urlcode编码方式</param>
    /// <param name="other_condition_express">其它查询条件表达式，采用DBExpress的$orderby表达式写法，传入时采用base64+urlcode编码方式</param>
    /// <returns></returns>
    public bool DoQueryList(ref string msg, ref object out_result, UnitParameter metaup, UnitParameter up, string id,
       bool is_filter_deleted = true, string parent_pk = "",
       string filter_column = "", string filter_value = "",
       string query_columns = "",
       string fixed_filter_express = "", string fixed_orderby_express = "", string other_condition_express = "")
    {
        var orderby_fixed_filter_express = FrameDLRObject.IsJsonThen(fixed_orderby_express, null, FrameDLRFlags.SensitiveCase);

        var where_fixed_filter_express = parseFixedExpress(fixed_filter_express);
        var where_other_condition_express = parseFixedExpress(other_condition_express);

        if (fixed_filter_express != "" && where_fixed_filter_express == null)
        {
            msg = "fixed_filter_express格式不正确";
            return false;
        }
        if (fixed_orderby_express != "" && orderby_fixed_filter_express == null)
        {
            msg = "fixed_orderby_express格式不正确";
            return false;
        }

        var q_columns = query_columns.Split(",", StringSplitOptions.RemoveEmptyEntries);

        var info = MetaDataUtilities.GetAllTables(metaup).Where(w => (w.MetaUID == id || w.MetaName == id) && w.IsCreated).FirstOrDefault();
        if (info == null)
        {
            msg = "元数据表不存在";
            return false;
        }
        string tablename = info.MetaName;
        string main_ref = ComFunc.nvl(info.MetaMainUID);
        string main_ref_show = ComFunc.nvl(info.MetaMainShowColumn);
        var columns = info.columns.Where(w => !w.IsVirsual).ToList();
        //过滤要抓取的栏位
        columns = q_columns.Length <= 0 ? columns : columns.Where(d => q_columns.Contains(d.MetaColumnName)).ToList();
        // 固定带上以下栏位
        columns.AddRange(MetaDataUtilities.FixColumnsModel);

        #region 构建select表达式
        FrameDLRObject express = FrameDLRObject.CreateInstance(@"{
$acttype : 'QueryByPage',
                }", EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);

        FrameDLRObject tableexpress = FrameDLRObject.CreateInstance(EFFC.Frame.Net.Base.Constants.FrameDLRFlags.SensitiveCase);
        //order by
        FrameDLRObject orderby = orderby_fixed_filter_express == null ? FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase) : orderby_fixed_filter_express;
        orderby.SetValue("sort_no", "asc");
        express.SetValue("$orderby", orderby);

        foreach (var c in columns)
        {
            //设定select的栏位
            express.SetValue($"{c.MetaColumnName}", true);
        }
        express.SetValue("$table", tablename);
        FrameDLRObject where = where_fixed_filter_express == null ? FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase) : where_fixed_filter_express;
        if (is_filter_deleted) where.SetValue("_is_deleted", 0);
        if (parent_pk != "") where.SetValue("_default_parent_pk", parent_pk);
        if (!string.IsNullOrEmpty(filter_column))
        {
            var fc = filter_column.Split(',', StringSplitOptions.RemoveEmptyEntries);
            var orlist = new List<FrameDLRObject>();
            where.SetValue("$or", orlist);
            foreach (var f in fc)
            {
                FrameDLRObject exp = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
                exp.SetValue("$like", filter_value);
                var fexp = FrameDLRObject.CreateInstance(FrameDLRFlags.SensitiveCase);
                fexp.SetValue(f, exp);
                orlist.Add(fexp);
            }
        }
        //其它查询条件
        if (where_other_condition_express != null)
        {
            RemoveFilterEmptry(where_other_condition_express);
            foreach (var key in where_other_condition_express.Keys)
            {
                if (ComFunc.nvl(where_other_condition_express.GetValue(key)) != "")
                {
                    where.SetValue(key, where_other_condition_express.GetValue(key));
                }
            }
        }
        //对特殊条件操作进行解析
        if (where.Items.Count > 0)
        {
            var tree_column = info.columns.Where(w => w.MetaDataType == "cadecase_tree" || w.MetaDataType == "multi_cadecase_tree").ToArray();
            var main_tree_column = info.columns.Where(w => w.MetaDataType == "cadecase_main" || w.MetaDataType == "multi_cadecase_main").ToArray();
            foreach (var item in where.Items)
            {
                if (item.Value is FrameDLRObject)
                {
                    var dobj = (FrameDLRObject)item.Value;
                    foreach (var k in dobj.Keys)
                    {
                        if (k == "$tree_in")
                        {
                            var c = tree_column.Where(w => w.MetaColumnName.ToLower() == item.Key.ToLower()).FirstOrDefault();
                            if (c == null)
                            {
                                var v = dobj.GetValue(k);
                                dobj.Remove(k);
                                dobj.SetValue("$in", v);
                                continue;
                            }

                            var newv = TreeIn(up, metaup, dobj.GetValue(k), c);
                            dobj.Remove(k);
                            dobj.SetValue("$in", newv);
                        }
                    }
                }
            }
        }

        if (where.Items.Count > 0)
        {
            express.SetValue("$where", where);
        }
        #endregion
        var result = DB.Excute(up, express, true);
        var data = result.QueryData<FrameDLRObject>();

        #region 处理各个栏位的UI数据和关联项
        SetRefColumnsText(metaup, up, info, columns, data, false);
        #endregion

        // 对数据中字符串的特殊符号做过滤
        data = FilterSpecialChar4List(data);
        out_result = new
        {
            code = "success",
            msg = "",
            total_count = result.TotalRow,
            page = result.CurrentPage,
            total_page = result.TotalPage,
            limit = result.Count_Of_OnePage,
            data = data
        };
        return true;
    }

    private object TreeIn(UnitParameter up, UnitParameter metaup, object value, MetaDataUtilities.MetaColumn column)
    {
        if (string.IsNullOrEmpty(column.MetaReference)) return value;
        var str_v = "";
        if (value is IEnumerable<object>) str_v = string.Join(",", (value as IEnumerable<object>));
        else if (value is string) str_v = ComFunc.nvl(value);
        else return value;

        var refparse = new RefExpress();
        var refexpress = refparse.ParseExpress(column.MetaReference);
        var rtn = new List<object>();
        Action<string> tree = null;
        tree = delegate (string p_values)
        {
            if (string.IsNullOrEmpty(p_values)) return;
            var l = (from t in DB.LamdaTable(up, refexpress.TableName, "a")
                     where t._default_parent_pk.within(p_values)
                     select new
                     {
                         v = t.column(refexpress.KeyColumn),
                         t._default_pk
                     }).GetQueryList(up);
            rtn.AddRange(l.ToList<object>().Select(d => (d as FrameDLRObject).GetValue("v")));
            tree(string.Join(",", l.Select(d => ComFunc.nvl(d.GetValue("_default_pk")))));
        };
        var list = (from t in DB.LamdaTable(up, refexpress.TableName, "a")
                    where t.column(refexpress.KeyColumn).within(str_v)
                    select new
                    {
                        v = t.column(refexpress.KeyColumn),
                        t._default_pk
                    }).GetQueryList(up);
        rtn.AddRange(list.ToList<object>().Select(d => (d as FrameDLRObject).GetValue("v")));
        tree(string.Join(",", list.Select(d => ComFunc.nvl(d.GetValue("_default_pk")))));

        return rtn.ToArray();
    }
    private List<FrameDLRObject> FilterSpecialChar4List(IEnumerable<FrameDLRObject> list)
    {
        return list.Select(d =>
        {
            foreach (var k in ((FrameDLRObject)d).Keys)
            {
                var v = d.GetValue(k);
                if (v != null)
                {
                    if (v is string)
                    {
                        d.SetValue(k, FilterSpecialChar(v));
                    }
                }
            }
            return d;
        }).ToList();
    }
    private string FilterSpecialChar(string str)
    {
        return str.Replace("", ComFunc.UrlEncode("")).Replace("", ComFunc.UrlEncode("")).Replace("", ComFunc.UrlEncode(""));
    }
    #endregion
}
}
